﻿package core {
	import com.greensock.TweenLite;
	
	import core.factory.GameBallFactory;
	import core.factory.PropFactory;
	import core.manager.SoundManager;
	import core.object.DropObject;
	import core.object.Flyer;
	import core.object.GameBall;
	import core.object.GameProp;
	
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.ui.Keyboard;
	import flash.utils.Dictionary;
	import flash.utils.Timer;
	import flash.utils.clearTimeout;
	import flash.utils.setTimeout;
	
    public class GameContainer extends Sprite {
        private var normal_speed:int;
        private var target_speed:int;
        private var move_speed:int;
        private var shooterPost:Array;
        private var balls:Array;
        private var rollInNum:int;
        private var shootedBalls:Array;
        private var crushBalls:Array;
        private var attractBalls:Array;
        private var ballsPost:Array;
        
       
        private var myParent:Game;
		
		private var canShoot:Boolean;
		private var shooter:Shooter;
		private var flyers:Array;
		private var map:Map;
		private var lines:int;
        private var moveMode:String;

        public static const process_Min:Number = (GameBall.radius * 0.007);
        public static const ball_D:Number = int(((GameBall.radius * 2) / process_Min));
        public static const speed_G:Number = -1.2;

        public static var MapData:Array;
		
		private var model:Model = Model.instance;

        public function GameContainer():void{
            super();
			this.addEventListener(Event.ADDED_TO_STAGE, this.addInStage);
        }
		
        private function addInStage(_arg1:Event):void{
			this.removeEventListener(Event.ADDED_TO_STAGE, this.addInStage);
            stage.focus = this;
            this.myParent = (this.parent as Game);
        }
		
        public function initGame():void{
			DisplayUtil.removeAllChildRen(this);
            this.initMap();
            this.initShooter();
            this.initData();
            this.addEvents();
        }
		
        private function initShooter():void{
            this.shooter = new Shooter();
            addChild(this.shooter);
            this.shooter.x = this.shooterPost[0].x;
            this.shooter.y = this.shooterPost[0].y;
        }
		
        private function initData():void{
			this.rollInNum = 500;
			model.clearNum = 0;
			this.addMoveSpeed = 0;
            this.canShoot = false;
            this.shootedBalls = [];
            this.flyers = [];
            this.normal_speed = (model.speedTimes * Config.speed_Min);
            this.move_speed = Config.GAME_BALL_ROLL_IN_SPEED;
            this.moveMode = "normal";
            SoundManager.instance.soundPlay("bgSound1");
        }
		
        private function initMap():void{
            var node:Array;
            var j:int;
            var _local4:int;
            var r:int;
            var _local6:Point;
            var _local7:Point;
            var _local8:Point;
            var _local9:int;
            var k:int;
            var anchorPoint:Array;
			this.map = new EasyMap();
            addChild(this.map);
            this.lines = this.map.lines;
            this.shooterPost = this.map.shooterPost;
            MapData = [];
            this.ballsPost = [];
            this.crushBalls = [];
            this.attractBalls = [];
            this.balls = [];
            var i:int;
            while (i < this.lines) {
                this.balls[i] = [];
                MapData[i] = [];
                this.ballsPost[i] = [];
                node = this.map.nodes[i];
                j = 0;
                while (j < (node.length - 2)) {
                    _local6 = ((j)==0) ? new Point(node[0][0], node[0][1]) : new Point(((node[j][0] + node[(j + 1)][0]) / 2), ((node[j][1] + node[(j + 1)][1]) / 2));
                    _local7 = new Point(node[(j + 1)][0], node[(j + 1)][1]);
                    _local8 = ((j)<=(node.length - 4)) ? new Point(((node[(j + 1)][0] + node[(j + 2)][0]) / 2), ((node[(j + 1)][1] + node[(j + 2)][1]) / 2)) : new Point(node[(j + 2)][0], node[(j + 2)][1]);
                    _local9 = Bezier.init(_local6, _local7, _local8, process_Min);
                    k = 1;
                    while (k <= _local9) {
                        anchorPoint = Bezier.getAnchorPoint(k);
                        MapData[i].push(anchorPoint);
                        k++;
                    }
                    j++;
                }
                _local4 = int((MapData[i].length / ball_D));
                r = 0;
                while (r < _local4) {
                    this.ballsPost[i].push(MapData[i][(ball_D * r)]);
                    r++;
                }
                i++;
            }
        }
		
		/**
		 * 
		 * @param line
		 * @param isPropBall
		 * 
		 */		
        private function addBall(line:int, isPropBall:Boolean):void{
            var ball:GameBall;
            var childIndex:int;
            var list:Array = this.balls[line];
            var count:int = list.length;
            if (isPropBall){
                if (count < 1 || list[0].id == 10){
                    return;
                }
                ball = new GameBall(10);
            } else {
                ball = GameBallFactory.createRandomGameBall();
            }
            var process:int = ((((count > 0)) && ((list[0].process < (ball_D * 2))))) ? (list[0].process - ball_D) : 0;
            list.unshift(ball);
            addChild(ball);
            ball.line = line;
            ball.onRoad = true;
            ball.process = process;
			ball.lineID = this.lineID;
        }
		
		/**
		 * 是否有可以消除的除,如果没有的话,就增加一列
		 * TODO 需要指定调用的位置
		 */ 
		private var deleteLength:int = 3;// n 个一消除
		
		public function checkAddNewLineBall():void {
			var flag:Boolean;
			var cache:Dictionary = new Dictionary(true);
			if(this.shooter.item && !this.shooter.item.isProp){
				cache[this.shooter.item.id] = int(cache[this.shooter.item.id]) + 1;
			}
			for(var i:int = 0; i < this.balls.length; i++){
				var items:Array = this.balls[i];
				for(var j:int = 0; j < items.length; j++){
					var ball:GameBall = items[j];
					cache[ball.id] = int(cache[ball.id]) + 1;
					if(cache[ball.id] >= deleteLength){
						flag = true;
						break;
					}
				}
			}
			for(var key:* in cache){
				if(cache[key] >= deleteLength){
					flag = true;
					break;
				}
			}
			if(!flag){
				this.lineID++;
				this.move_speed = 200;
				this.addEventListener(Event.ENTER_FRAME,ballRollInHandler);
			}
		}
		
        private function flyerRollIn():void{
            var flyer:Flyer;
            if (this.flyers.length > 0){
                return;
            }
            var index:int;
            while (index < this.lines) {
                flyer = new Flyer();
                addChild(flyer);
                flyer.onRoad = true;
                flyer.line = index;
                flyer.process = 0;
                this.flyers[index] = flyer;
                index++;
            }
            addEventListener(Event.ENTER_FRAME, this.flyersMove);
        }
		
        private function ballRollInHandler(event:Event):void{
            var i:int;
            var count:int;
            var index:int;
            while (index < this.balls.length) {
                i = 0;
                while (i < this.balls[index].length) {
					var ball:GameBall = this.balls[index][i];
					ball.process = ball.process + this.move_speed;
					if(ball.lineID == this.lineID){
						count++;
					}
                    i++;
                }
                index++;
            }
            this.checkAddBall();
            if (count >= this.rollInNum){
				this.checkAttractBall();// 需要重新检测数据
                this.removeEventListener(Event.ENTER_FRAME, this.ballRollInHandler);
				this.removeEventListener(Event.ENTER_FRAME, this.frameHandler);
                this.addEventListener(Event.ENTER_FRAME, this.frameHandler);
                this.canShoot = true;
            }
        }
		
		private var lineID:int;
		
		private var lastMouseX:Number;
        private function frameHandler(event:Event):void{
			if(this.shooterMoveabled){
				var direction:int = 0;
				if(lastMouseX < mouseX){
					direction = -1;
				}else if(lastMouseX > mouseX){
					direction = 1;
				}
				var flag:Boolean = this.shooter.catchDrop(this.dropObject);
				if(flag){
					if(this.dropObject.isImmediately){
						this.handProp(this.dropObject);
					}
					this.dropObject.dispose();
					this.dropObject = null;
				}
				this.shooter.x = mouseX;
				this.lastMouseX = this.shooter.x;
			}
			if(this.originalMoveSpeed == 0){
				this.addSpeed();
			}
			if(ballMoveabled){
				this.ballsMove();
			}
			this.shootBallMove();
			this.attractMove();
			this.insertMove();
			this.checkAddNewLineBall();
			this.setHighlightGameBall(direction);
        }
		
		private function handProp(value:DropObject):void {
			switch(value.id){
				case 2008:
					this.shooterMoveabled = false;
					clearID = setTimeout(stopShootHandler,2000);
					break;
				case 2009:
					model.combo = 0;
					break;
				case 2010:
					addMoveSpeed = 10;
					clearID = setTimeout(removeAddMoveSpeed,3000);
					break;
				case 2011:
					ballMoveabled = false;
					clearID = setTimeout(resetBallMoveabled,15000);
					break;
				case 2012:
					//this.originalMoveSpeed = this.move_speed;
					//this.move_speed = -50;
					this.moveMode = Config.MOVE_MODE_BACK;
					modeID = setTimeout(changeNormalMoveMode,5000);
					break;
				case 2013:
					this.randomShootGameBall();
					break;
				case 2015:
					this.flyerRollIn();
					break;
					
			}
		}
		
		/**
		 * 从最下面随机发射N个小球 
		 * 
		 */		
		private function randomShootGameBall():void {
			for(var i:int = 0; i <= 4; i++){
				var ball:GameBall = GameBallFactory.createRandomGameBall();
				ball.y = this.shooter.y;
				ball.x = 150 + Math.random() * 500;
				this.addChild(ball);
				this.shootedBalls.push(ball);
				
			}
		}
		
        private function checkAddBall():void{
            var list:Array;
            var count:int;
            if (model.clearNum >= model.totalNum){
                return;
            }
            var index:int;
            while (index < this.lines) {
                list = this.balls[index];
                count = list.length;
                if (count == 0 || (list[0].process > ball_D)){
                    this.addBall(index, false);
                }
                index++;
            }
        }
		
        private function flyersMove(event:Event):void{
            var index:int;
            while (index < this.flyers.length) {
                this.flyerMove(this.flyers[index]);
                index++;
            }
            index = 0;
            while (index < this.flyers.length) {
                if (this.flyers[index]){
                    return;
                }
                index++;
            }
            this.removeEventListener(Event.ENTER_FRAME, this.flyersMove);
        }
		
        private function flyerMove(value:Flyer):void{
            if (!value){
                return;
            }
            var line:int = value.line;
            var list:Array = this.balls[line];
            if (value.onRoad && this.canShoot){
                value.process = (value.process + Config.FLY_SPEED);
                this.pickUpBall(value);
                if (value.process > list[(list.length - 1)].process){
                    value.onRoad = false;
                }
            } else {
                value.angle = (value.angle + (((Math.PI * 0.5) - value.angle) * 0.25));
                value.x = (value.x + (Math.cos(value.angle) * 10));
                value.y = (value.y + (Math.sin(value.angle) * 10));
                if (!value.onRoad){
                    if (value.x < -100 || value.x > Config.WIDTH + 100 || value.y < -100 || value.y > Config.HEIGHT + 100){
                        removeChild(value);
						this.flyers.splice(this.flyers.indexOf(value),1);
                    }
                }
            }
        }
        private function pickUpBall(value:Flyer):void{
            var startIndex:int;
            var ball:GameBall;
            var angle:Number;
            var toX:Number;
            var toY:Number;
            var dist:Number;
            var line:int = value.line;
            var list:Array = this.balls[line];
            var index:int;
            var count:int = list.length;
            while (index < count) {
				var item:GameBall = list[index];
                if (item.process > value.process && item.process < (value.process + ball_D)){
                    startIndex = index;
                    ball = list[startIndex];
                    break;
                }
                index++;
            }
            if (ball && ball.onRoad){// TODO 看具体需求,如果不需要就去掉了
                SoundManager.instance.soundPlay("pick");
                list.splice(startIndex, 1);
                setChildIndex(ball, (numChildren - 1));
                angle = (value.angle + Math.PI);
                toX = ((600 * Math.cos(angle)) + ball.x);
                toY = ((600 * Math.sin(angle)) + ball.y);
                dist = (Math.sqrt((((ball.x - toX) * (ball.x - toX)) + ((ball.y - toY) * (ball.y - toY)))) * 2);
                TweenLite.to(ball, 1, {x:toX, y:toY, onComplete:this.onMoveOut, onCompleteParams:[ball]});
                this.afterClear();
            }
        }
		
        private function onMoveOut(value:GameBall):void{
            removeChild(value);
        }
		
        private function addSpeed():void{
            switch (this.moveMode){
                case Config.MOVE_MODE_NORMAL:
                    this.target_speed = this.normal_speed;
                    break;
                case Config.MOVE_MODE_FORWARD:
                    this.target_speed = (this.normal_speed * 3);
                    break;
                case Config.MOVE_MODE_BACK:
                    this.target_speed = (-(this.normal_speed) * 3);
                    break;
            }
            /*var increase:Number = (this.target_speed - this.move_speed);
            if (increase > 50){
                increase = 10;
            } else  if (increase > 10){
                increase = 2;
            } else  if (increase > 1){
                increase = 1;
            } else  if (increase < -50){
                increase = -10;
            } else  if (increase < -10){
                increase = -2;
            } else if (increase < -1){
                increase = -1;
            }*/
            this.move_speed = this.target_speed + this.addMoveSpeed;
        }
        private function ballsMove():void{
            if (this.move_speed == 0){
                return;
            }
            if (this.moveMode == Config.MOVE_MODE_NORMAL){
                this.normalMove();
            } else {
                this.autoMove();
            }
            this.checkIsOver();
        }
		
        private function normalMove():void{
            var index:int;
            while (index < this.lines) {
                this.pushBallMove(index, 0, this.move_speed);
                index++;
            }
        }
		
        private function autoMove():void{
            var count:int;
            var i:int;
            var ball:GameBall;
            var index:int;
			var changeModeabled:Boolean = false;
            while (index < this.lines) {
                count = this.balls[index].length;
                i = 0;
                while (i < count) {
                    ball = this.balls[index][i];
					ball.process = (ball.process + this.move_speed);
					if(ball.process == 0){
						changeModeabled = true;
					}
                    i++;
                }
                index++;
            }
			if(changeModeabled){
				this.changeNormalMoveMode();
			}
        }
		
        private function pushBallMove(_arg1:int=0, _arg2:int=0, _arg3:int=1):void{
            if (_arg3 == 0){
                return;
            }
            var items:Array = this.balls[_arg1];
            if (items.length < 1){
                return;
            }
            var list:Array = new Array();
            list.push(items[_arg2]);
            var count:int = items.length;
            var index:int = (_arg2 + 1);
            while (index < count) {
				var ball:GameBall = items[index];
				var nextBall:GameBall = items[(index - 1)];
                if (((!(ball.onRoad)) || (((ball.process - nextBall.process) > (ball_D + Config.error_process))))){
                    break;
                }
                list.push(items[index]);
                index++;
            }
            list[0].process = (list[0].process + _arg3);
            count = list.length;
            index = 1;
            while (index < count) {
                list[index].process = (list[(index - 1)].process + ball_D);
                index++;
            }
        }
		
		private var lastList:Array; // 最后一个清除的数组
        private function mouseDownHandler(event:MouseEvent):void{
			if(!this.canShoot) {
				return;
			}
			if(this.shooter.item){
				this.shoot(this.shooter.item);
			}else if(this.shooter.prop){
				this.shoot(this.shooter.prop);
			}else {
				this.setHighlightGameBall(0);
				if(this.lastList == null){// 没有选中任何球
					return;
				}
				if(this.lastList.length == 1){// 普的拿的数据
					this.balls[0].splice(this.balls[0].indexOf(this.lastList[0]),1);
					this.lastList[0].dispose();
					this.shooter.addItem(this.lastList[0]);
				}
				if(this.shooter.prop){// TODO 这里可能会有一个bug
					this.removeBalls(this.lastList);
				}else {
					this.checkClear(this.lastList[0]);
				}
			}
        }
		
		/**
		 * TODO bug
		 * @param direction
		 * 
		 */		
		public function setHighlightGameBall(direction:int):void {
			/*if(this.shooter.item == null || this.shooter.prop = null){
				return;
			}*/
			var target:DisplayObject = this.shooter.prop != null ? this.shooter.prop : this.shooter.line;
			var isMulti:Boolean = this.shooter.prop != null ? true : false;
			var hitTestBalls:Array = this.getHitTestBall(target,isMulti,direction);// 这里需要做处理
			var temp:GameBall;
			if(lastList != null){
				for each(temp in lastList){
					temp.highlight = false;
				}
			}
			lastList = hitTestBalls;
			for each(temp in lastList){
				temp.highlight = true;
			}
			this.updateLine(direction);
			
		}
		
		public function updateLine(direction:int):void {
			var list:Array = this.getHitTestBall(this.shooter.line,false,direction);
			if(list == null){
				this.shooter.updateLine(Config.LINE_MAX_HEIGHT);
			}else {
				var ball:GameBall = list[0];
				this.shooter.updateLine(this.shooter.y - ball.y + ball.height);
			}
		}
		
		private function getHitTestBall(target:DisplayObject,isMulti:Boolean,direction:int):Array {
			var result:Array = [];
			var position:Point = this.shooter.localToGlobal(new Point(target.x,target.y));
			for(var i:int = 0; i < this.lines; i++){
				var items:Array = this.balls[i];
				for(var j:int = 0; j < items.length; j++){
					var temp:GameBall = items[j];
					if(temp.hitTestObject(target)){
						result.push(temp);
					}
				}
			}
			if(isMulti){
				return result;
			}else {
				if(result.length == 0){
					return null;
				}else if(result.length == 1){
					return result;
				}else {
					result.sort(sortFunc);// 排列y值
					var b1:GameBall = result[0];
					var b2:GameBall = result[1];
					if(b1.y - b2.y > GameBall.radius){// 如果相差太大,那么肯定是需要取最前面的一个
						return [b1];
					}
					if(direction == 1){// 是根据mouse的移动的数值去计算的
						return [b2];
					}else if(direction == -1){
						return [b1];
					}else{
						if(this.move_speed < 0){
							return [b1];
						}else {
							return [b2];
						}
					}
				}
			}
			return null;
		}
		
		private function sortFunc(a:GameBall,b:GameBall):int {
			if(a.y > b.y){
				return -1;
			}
			if(a.y < b.y){
				return 1;
			}
			return 0;
		}
		
		private var dropObject:DropObject;
		
		private var clearID:uint;
		private var addMoveSpeed:Number = 0;
		private var ballMoveabled:Boolean = true;
		private var originalMoveSpeed:Number = 0;
        public function shoot(value:GameBall):void{
			this.canShoot = false;
			if(value is GameProp && value.id != 9){
				var kind:int = GameProp(value).kind;
				this.setHighlightGameBall(0);
				if(kind == 2001 || kind == 2002){// 线和炸弹
					this.removeBalls(this.lastList);
				}else if(kind == 2003){
					this.setNewId(1);// 变色
				}
				this.canShoot = true;
			}else {
				value = value.clone();
				value.x = this.shooter.x - GameBall.radius;// TODO bug 
				value.y = this.shooter.y;
				addChild(value);
				this.shooter.reset();
	            this.shootedBalls.push(value);
				/*dropObject = PropFactory.generate();
				dropObject.x = 500;
				dropObject.y = 100;
				this.addChild(dropObject);
				dropObject.drop();
				if(value.id == 9){
					this.shooter.removeProp();
				}*/
			}
        }
		
		private var modeID:int;
		
		private function changeNormalMoveMode():void {
			this.moveMode = Config.MOVE_MODE_NORMAL;
			clearTimeout(modeID);
		}
		
		private function resetBallMoveabled():void {
			this.ballMoveabled = true;
		}
		
		private function removeAddMoveSpeed():void {
			this.addMoveSpeed = 0;
		}
		
		private var shooterMoveabled:Boolean = true;
		private function stopShootHandler():void {
			this.shooterMoveabled = true;
			this.canShoot = true;
		}
		
		private function setNewId(value:int):void {
			for(var i:int = 0; i < this.lines; i++){
				var items:Array = this.balls[0];
				for(var j:int = 0; j < this.lastList.length; j++){
					var ball:GameBall = this.lastList[j];
					var index:int = items.indexOf(ball);// 在当前balls列表的索引
					if(index != -1){
						items[index].id = value;
					}
				}
			}
		}
		
        private function checkHasGap(value:GameBall):void{
            var list:Array;
            var count:int;
            var r:int;
            var i:int;
            var position:Array;
            var px:Number;
            var py:Number;
            if (value.id == 8){
                return;
            }
            if (value.throwed){
                return;
            }
            var targetX:Number = value.x;
            var targetY:Number = value.y;
            var index:int;
            while (index < this.lines) {
                list = this.balls[index];
                if (list.length < 1){
                } else {
                    count = this.ballsPost[index].length;
                    i = 0;
                    while (i < count) {
                        position = this.ballsPost[index][i];
                        px = position[0];
                        py = position[1];
                        if ((((targetX - px) * (targetX - px)) + ((targetY - py) * (targetY - py))) < ((4 * GameBall.radius) * GameBall.radius)){
                            r = (i * ball_D);
                            if ((((list[(list.length - 1)].process > r)) && ((list[0].process < r)))){
                                value.across = (value.across + 1);
                            }
                            break;
                        }
                        i++;
                    }
                }
                index++;
            }
        }
		
		public function isWrap(value:GameBall):Boolean {
			if(value.x > 0 && value.x < Config.WIDTH && value.y > 0 && value.y < Config.HEIGHT){
				return false;
			}
			return true;
		}
        private function shootBallMove():void{
            var ball:GameBall;
            var angle:Number;
            var collision:Array;
            var index:int;
            var list:Array;
            var nearstBall:Array;
            var line:int;
            var ballIndex:int;
            var target:GameBall;
            var diff:int;
            var xx:Number;
            var yy:Number;
            var dist:Number;
            var toX:Number;
            var toY:Number;
            var dist2:Number;
            var flag:Boolean;
            if (this.shootedBalls.length < 1){
                return;
            }
			var count:int = (this.shootedBalls.length - 1);
            while (count >= 0) {
                ball = this.shootedBalls[count];
				if(!isWrap(ball)){
                    angle = ball.angle;
                    ball.y = ball.y - Config.shoot_speed;
                    if (ball.throwed){
                        ball.speedY = (ball.speedY + speed_G);
                        ball.tallness = (ball.tallness + ball.speedY);
                        if (ball.tallness > 0){
                            return;
                        }
                        ball.tallness = 0;
                        ball.x = ball.targetX;
                        ball.y = ball.targetY;
                        ball.throwed = false;
                    }
                    collision = this.cheackCollision(ball);
                    if (collision && collision.length > 0){
                        index = 0;
                        while (index < collision.length) {
                            if (this.balls[collision[index][0]][collision[index][1]].id == 10){
                                SoundManager.instance.soundPlay("blackBall");
                                ball.explode(10);
                                this.shootedBalls.splice(count, 1);
                            }
                            index++;
                        }
                        if (ball.throwed){
                            ball.tallness = 0;
                        }
                        if (ball.id == 8){
                            list = [];
                            index = 0;
                            while (index < collision.length) {
                                list.push(this.balls[collision[index][0]][collision[index][1]]);
                                index++;
                            }
                            model.combo = 0;
                            this.removeBalls(list);
                        } else {
                            this.putRightPost(ball, collision);
                            nearstBall = this.findNearstBall(ball, collision);
                            line = nearstBall[0];
                            ballIndex = nearstBall[1];
                            target = this.balls[line][ballIndex];
                            diff = (target.process - ball_D);
                            if (diff < 0){
                                diff = 0;
                            }
                            xx = MapData[line][diff][0];
                            yy = MapData[line][diff][1];
                            dist = (((ball.x - xx) * (ball.x - xx)) + ((ball.y - yy) * (ball.y - yy)));
                            toX = MapData[line][(target.process + ball_D)][0];
                            toY = MapData[line][(target.process + ball_D)][1];
                            dist2 = (((ball.x - toX) * (ball.x - toX)) + ((ball.y - toY) * (ball.y - toY)));
                            flag = (dist < dist2);
                            this.insertBalls(ball, nearstBall, flag);
							this.canShoot = true;
                            this.shootedBalls.splice(count, 1);
                        }
                    } else {
                        this.checkHasGap(ball);
                    }
                } else {
                    removeChild(ball);
                    this.shootedBalls.splice(count, 1);
					this.shooter.reduction();
					this.canShoot = true;
                }
                count--;
            }
        }
        private function findNearstBall(value:GameBall, list:Array):Array{
            var p3:int;
            var p4:int;
            var target:GameBall;
            var dist2:Number;
            if (list.length == 1){
                return list[0];
            }
            var ball:GameBall = this.balls[list[0][0]][list[0][1]];
            var dist1:Number = Util.getDist(value, ball);
            var p1:int = list[0][0];
            var p2:int = list[0][1];
            var index:int = 1;
            while (index < list.length) {
                p3 = list[index][0];
                p4 = list[index][1];
                target = this.balls[p3][p4];
                dist2 = Util.getDist(value, target);
                if (dist2 < dist1){
                    ball = target;
                    dist1 = dist2;
                    p1 = p3;
                    p2 = p4;
                }
                index++;
            }
            return [p1, p2];
        }
        private function putRightPost(value:GameBall, items:Array):void{
            var list:Array;
            var ball:GameBall;
            var angle:Number;
            var sqrt:Number;
            var index:int;
            while (index < items.length) {
                list = this.balls[items[index][0]];
                ball = list[items[index][1]];
                angle = Math.atan2((value.y - ball.y), (value.x - ball.x));
                sqrt = Math.sqrt(Util.getDist(value, ball));
                value.x = (value.x + (((GameBall.radius * 2) - sqrt) * Math.cos(angle)));
                value.y = (value.y + (((GameBall.radius * 2) - sqrt) * Math.sin(angle)));
                index++;
            }
        }
		
		
        private function cheackCollision(value:GameBall):Array{
            var list:Array;
            var count:int;
            var dist:Number;
            var result:Array = [];
            var index:int;
            while (index < this.balls.length) {
                list = this.balls[index];
                count = (list.length - 1);
                while (count >= 0) {
                    if (index != 1){
                        dist = Util.getDist(value, list[count]);
                        if (dist <= ((GameBall.radius * GameBall.radius) * 4)){
                            result.push([index, count]);
                        }
                    }
                    count--;
                }
                index++;
            }
            return result;
        }
		
		/**
		 * 
		 * 
		 */		
        private function insertMove():void{
            var ball:GameBall;
            var ball1:GameBall;
            var ball0:GameBall;
            var line:int;
            var process:int;
            var list:Array;
            var tx:Number;
            var ty:Number;
            var newAngle:Number;
            var angle:Number;
            var dist:Number;
            var speed:Number;
            var rIndex:int;
            var _local16:int;
            var indexOf:int;
            var addProcess:int;
            var count:int = this.crushBalls.length;
            if (count < 1){
                return;
            }
            var index:int = (count - 1);
            while (index >= 0) {
                ball = this.crushBalls[index][0];
                ball1 = this.crushBalls[index][1];
                ball0 = this.crushBalls[index][2];
                line = ball.line;
                if (ball1){
                    process = (ball1.process + ball_D);
                } else {
                    if (ball0){
                        process = (ball0.process - ball_D);
                    } else {
                        process = ball.process;
                    }
                }
                if (process < 0){
                    process = 0;
                }
                ball.process = process;
                list = MapData[line][process];
                tx = list[0];
                ty = list[1];
                newAngle = list[2];
                angle = Math.atan2((ty - ball.y), (tx - ball.x));
                dist = Math.sqrt((((ball.x - tx) * (ball.x - tx)) + ((ball.y - ty) * (ball.y - ty))));
                speed = (Config.insert_speed + (Math.abs(this.move_speed) * process_Min));
                if (dist > speed){
                    ball.x = (ball.x + (Math.cos(angle) * speed));
                    ball.y = (ball.y + (Math.sin(angle) * speed));
                    ball.angle = ((newAngle - ball.angle) * 0.5);
                    if (ball0){
                        rIndex = this.balls[line].indexOf(ball0);
                        if (rIndex != -1){
                            _local16 = int((((process + ball_D) - ball0.process) * 0.5));
                            this.pushBallMove(line, rIndex, _local16);
                        }
                    }
                } else {
                    ball.onRoad = true;
                    ball.process = process;
                    if (ball0){
                        indexOf = this.balls[line].indexOf(ball0);
                        if (indexOf != -1){
                            addProcess = ((process + ball_D) - ball0.process);
                            this.pushBallMove(line, indexOf, addProcess);
                        }
                    }
                    this.crushBalls.splice(index, 1);
                    model.combo = 0;
                    this.checkClear(ball);
                }
                index--;
            }
        }
		
		
        private function insertBalls(value:GameBall, list:Array, _arg3:Boolean):void{
            var startIndex:int;
            var leftItem:GameBall;
            var rightItem:GameBall;
            var line:int = list[0];
            var index:int = list[1];
            var items:Array = this.balls[line];
            if (_arg3){
                startIndex = index;
                rightItem = items[index];
                if (((items[(index - 1)]) && (((items[index].process - items[(index - 1)].process) < (ball_D * 2))))){
                    leftItem = items[(index - 1)];
                }
            } else {
                startIndex = (index + 1);
                leftItem = items[index];
                if (((items[(index + 1)]) && (((items[(index + 1)].process - items[index].process) < (ball_D * 2))))){
                    rightItem = items[(index + 1)];
                }
            }
            items.splice(startIndex, 0, value);
            value.line = line;
            this.crushBalls.push([value, leftItem, rightItem]);
            SoundManager.instance.soundPlay("insert");
            this.checkAttractBall();
        }
		
		/**
		 * 
		 * @param value
		 * 
		 */		
        private function checkClear(value:GameBall):void{
            var list:Array;
            if (value.id == 9){
                list = this.allPurposeClear(value);
            } else {
                list = this.findNoramlBalls(value);
            }
            if (list){
                model.combo++;
                this.removeBalls(list);
            } else {
                value.across = 0;
                this.checkAttractBall();
            }
        }
		
		/**
		 * 消除相邻的球
		 */ 
        private function allPurposeClear(value:GameBall):Array{
            var id:int;
            var count:int;
            var line:int = value.line;
            var items:Array = this.balls[line];
            var index:int = items.indexOf(value);
            var result:Array = [value];
            var temp:Array = [];
            if (items[(index - 1)]){
                if (items[(index - 1)].id != 10){
                    temp.push(items[(index - 1)].id);
                }
            }
            if (items[(index + 1)]){
                temp.push(items[(index + 1)].id);
            }
            if (temp.length > 1){
                if (temp[0] == temp[1]){
                    temp.pop();
                }
            }
            var i:int;
            while (i < temp.length) {
                id = temp[i];
                count = (index + 1);
                while (count < items.length) {
                    if (!items[count]){
                        break;
                    }
                    if (items[count].id != id){
                        break;
                    }
                    if ((items[count].process - items[(count - 1)].process) > (ball_D + Config.error_process)){
                        break;
                    }
                    result.push(items[count]);
                    count++;
                }
                count = (index - 1);
                while (count >= 0) {
                    if (!items[count]){
                        break;
                    }
                    if (items[count].id != id){
                        break;
                    }
                    if ((items[(count + 1)].process - items[count].process) > (ball_D + Config.error_process)){
                        break;
                    }
                    result.push(items[count]);
                    count--;
                }
                i++;
            }
            return result;
        }
		
        private function findNoramlBalls(value:GameBall):Array{
            var line:int = value.line;
            var list:Array = this.balls[line];
            var index:int = list.indexOf(value);
            if (index == -1){
                return null;
            }
            var result:Array = new Array();
            result.push(value);
            var id:int = value.id;
            var nextIndex:int = (index + 1);
            while (list[nextIndex]) {
                if (list[nextIndex].id == id){
                    if (!list[nextIndex].onRoad){
                        return null;
                    }
                    if ((list[nextIndex].process - list[(nextIndex - 1)].process) <= (ball_D + Config.error_process)){
                        result.push(list[nextIndex]);
                        nextIndex++;
                    } else {
                        break;
                    }
                } else {
                    break;
                }
            }
            nextIndex = (index - 1);
            while (list[nextIndex]) {
                if (list[nextIndex].id == id){
                    if (!list[nextIndex].onRoad){
                        return (null);
                    }
                    if ((list[(nextIndex + 1)].process - list[nextIndex].process) <= (ball_D + Config.error_process)){
                        result.push(list[nextIndex]);
                        nextIndex--;
                    } else {
                        break;
                    }
                } else {
                    break;
                }
            }
            if (result.length >= deleteLength){
                return result;
            }
            return null;
        }
		
        private function removeBalls(value:Array):void{
            var ball:GameBall;
            var line:int;
            var startIndex:int;
            var count:int = value.length;
            var index:int;
            while (index < count) {
                ball = value[index];
                if (ball.id == 9){
                    ball.explode(value[1].id);// TODO bug 
                } else {
                    ball.explode();
                }
                line = ball.line;
                startIndex = this.balls[line].indexOf(ball);
                this.balls[line].splice(startIndex, 1);
                index++;
			}
            SoundManager.instance.soundPlay("clear");
            this.afterClear();
        }
		
		/**
		 * 检测最后还有N个球,如果还有N == 1时,就会自动消除掉
		 */ 
        private function afterClear():void{
            var flag:Boolean;
            var i:int;
            while (i < this.lines) {
                if (this.balls[i].length == 1){
                    this.balls[i][0].explode(10);
                    this.balls[i] = [];
                } else {
                    if (this.balls[i].length > 1){
                        flag = false;
                    }
                }
                i++;
            }
            if (model.clearNum >= model.totalNum){
                this.flyerRollIn();
                this.addBlackBall();
                if (flag){
                    this.canShoot = false;
                    this.gamePass();
                } else {
                    this.checkAttractBall();
                }
            } else {
                this.checkAttractBall();
            }
        }
        private function addBlackBall():void{
            var index:int;
            while (index < this.lines) {
                this.addBall(index, true);
                index++;
            }
        }
		
        private function checkAttractBall():void{
            var list:Array;
            var count:int;
            var j:int;
            var ball:GameBall;
            var nextBall:GameBall;
            var i:int;
            while (i < this.balls.length) {
                list = this.balls[i];
                count = list.length;
                j = 0;
                while (j < (count - 1)) {
                    ball = list[j];
                    nextBall = list[(j + 1)];
                    if (ball.id == nextBall.id){
                        if ((nextBall.process - ball.process) > ball_D){
                            setTimeout(this.addAttractBall, 50, nextBall);
                        }
                    }
                    j++;
                }
                i++;
            }
        }
        private function addAttractBall(value:GameBall):void{
            if (!value){
                return;
            }
            var line:int = value.line;
            var items:Array = this.balls[line];
            var index:int = items.indexOf(value);
            if (index == -1){
                return;
            }
            if (items[(index - 1)].id != value.id){
                return;
            }
            if ((items[index].process - items[(index - 1)].process) <= ball_D){
                return;
            }
            if (this.attractBalls.indexOf(value) == -1){
                this.attractBalls.push(value);
            }
        }
		
        private function attractMove():void{
            var ball:GameBall;
            var line:int;
            var list:Array;
            var index:int;
            var dist:int;
			if(this.attractBalls == null){
				return;
			}
			if(this.attractBalls.length < 1){
				return;
			}
            var count:int = (this.attractBalls.length - 1);
            while (count >= 0) {
                ball = this.attractBalls[count];
                line = ball.line;
                list = this.balls[line];
                index = list.indexOf(ball);
                if (index != -1 && list[index - 1]){
                    if (ball.id == list[index - 1].id){
                        dist = ((ball.process - list[(index - 1)].process) - ball_D);
                        if (dist > Config.ATTRACT_SPEED){
                            dist = Config.ATTRACT_SPEED;
                        }
                        this.pushBallMove(line, index, -dist);
                        if ((ball.process - list[(index - 1)].process) <= ball_D){
                            this.checkClear(ball);
                            this.attractBalls.splice(count, 1);
                        }
                    } else {
                        this.attractBalls.splice(count, 1);
                    }
                }
                count--;
            }
        }
		
        private function gamePass():void{
            SoundManager.instance.soundPlay("pass");
            this.removeEvents();
            this.clearAllBalls();
        }
		
        private function ballRollOut(event:Event):void{
            var count:int;
            var index:int;
			var ball:GameBall;
            while (index < this.lines) {
                count = (this.balls[index].length - 1);
                while (count >= 0) {
					ball = this.balls[index][count];
					ball.process = ball.process + Config.GAME_BALL_ROLL_OUT_SPEED;
                    if (ball.process > (MapData[index].length - 20)){
						ball.dispose();
                        this.balls[index].splice(count, 1);
                    }
                    count--;
                }
                index++;
            }
            index = 0;
            while (index < this.lines) {
                if (this.balls[index].length > 0){
                    return;
                }
                index++;
            }
            removeEventListener(Event.ENTER_FRAME, this.ballRollOut);
            this.gameOver();
        }
        
		/**
		 * 检测是否结束
		 */ 
        private function checkIsOver():void{
            var items:Array;
            var index:int;
            while (index < this.lines) {
                items = this.balls[index];
                if (items.length < 1){
                } else {
                    if (items[(items.length - 1)].process > (MapData[index].length - (ball_D * 5))){
                        this.map.openHole(index);
                        if (items[(items.length - 1)].process > (MapData[index].length - ball_D)){
                            this.overPlay();
                            break;
                        }
                    } else {
                        this.map.closeHole(index);
                    }
                }
                index++;
            }
        }
		
        private function clearAllBalls():void{
            this.shooter.clearBalls();
            this.clearShooted();
        }
        private function overPlay():void{
            this.canShoot = false;
            this.removeEvents();
            SoundManager.instance.soundPlay("hole");
            addEventListener(Event.ENTER_FRAME, this.ballRollOut);
            var index:int;
            while (index < this.lines) {
                this.map.openHole(index);
                index++;
            }
        }
        private function gameOver():void{
			model.life = (model.life - 1);
            if (model.life < 1){
            } else {
                setTimeout(this.initGame, 1000);
            }
        }
		
        private function clearShooted():void{
            var ball:GameBall;
            var count:int = this.shootedBalls.length;
            if (count < 1){
                return;
            }
            var index:int = (count - 1);
            while (index >= 0) {
                ball = this.shootedBalls[index];
                this.removeChild(ball);
                this.shootedBalls.splice(index, 1);
                index--;
            }
        }
		
		private function addEvents():void{
			this.checkAddNewLineBall();
			stage.addEventListener(MouseEvent.MOUSE_DOWN, this.mouseDownHandler);
		}
		
        private function removeEvents():void{
            this.removeEventListener(Event.ENTER_FRAME, this.frameHandler);
            stage.removeEventListener(MouseEvent.MOUSE_DOWN, this.mouseDownHandler);
        }
    }
}
